#pragma once
#include "Sock.hpp"

#include <functional>
#include <vector>

namespace FangZhang_Server
{
    using func_t = std::function<void(int)>;

    // 声明一下，不然ThreadData里面的Server*用不了 
    class Server;

    // 创建线程后，执行任务时需要有很多的字段，单是pthread_create
    // 的最后一个参数想要用这些字段的话得用一个类来封装
    class ThreadData
    {
    public:
        ThreadData(int serverSock, Server *serverPtr)
            : _serverSock(serverSock), _serverPtr(serverPtr)
        {}

    public:
        int _serverSock; // IO的fd
        Server *_serverPtr; // Server指针用来让ThreadRoutine访问其中的字段
    };

  
    class Server
    {
    private:
            // 线程执行方法
        static void *ThreadRoutine(void *args)
        {
            pthread_detach(pthread_self());

            ThreadData* ptd = static_cast<ThreadData*>(args);
            ptd->_serverPtr->Execute(ptd->_serverSock);
            
            // 执行完任务，关闭文件描述符
            close(ptd->_serverSock);

            // 释放ptd指向空间
            delete ptd;

            return nullptr;
        }


    public:
        // 初始化就传 IP + port
        Server(uint16_t port, const std::string &ip = "0.0.0.0")
        {
            // 1. 创建套接字
            _listenSock = _sock.Socket();

            // 2. bind绑定
            _sock.Bind(_listenSock, port, ip);

            // 3. 设置套接字为listen状态
            _sock.Listen(_listenSock);
        }

            //线程执行方法中的所有方法
        void Execute(int serverSock)
        {
            // 所有的任务都执行一次
            for(auto &f : _func)
            {
                f(serverSock);
            }
        }

            // 添加任务
        void AddService(func_t func)
        {
            _func.push_back(func);
        }

        void StartServer()
        {
            while (1)
            {
                // 客户端的IP + port
                std::string clientIp;
                uint16_t clientPort;

                // 返回IO的fd
                int serverSock = _sock.Accept(_listenSock, clientIp, clientPort);
                if (serverSock == -1)
                    continue;

                // 创建线程执行任务
                ThreadData* ptd = new ThreadData(serverSock, this);
                pthread_t pid;
                                                /*参数传ThreadData能得到更多有用*/
                pthread_create(&pid, nullptr, ThreadRoutine, ptd);
            }
        }

    private:
        int _listenSock; // 首次创建套接字的文件描述符
        Sock _sock; // 套接字接口
        std::vector<func_t> _func; // 线程任务列表
    };
}
